package com.ymdx.util.tool;

import com.ymdx.entity.IdEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 强力反射工具类.
 * 
 * @author hcq
 * 
 * @version 1.0
 */
public class ReflectUtils {
	// ~ Instance fields =======================================================
	private static final Logger log = LoggerFactory
			.getLogger(ReflectUtils.class);

	// ~ Constructor ===========================================================

	// ~ Methods ===============================================================

	/**
	 * 直接读取对象的属性值,public/protected/private均可,无需get方法的存在.
	 * 
	 * @param object
	 * @param fieldName
	 * @return
	 */
	public static Object getFieldValue(final Object object,
			final String fieldName) {
		Field field = getDeclaredField(object, fieldName);
		if (field == null)
			throw new IllegalArgumentException("can not find field : "
					+ fieldName + " on object : " + object + ".");
		makeFieldAccessible(field);// 使属性可访问
		Object result = null;
		try {
			result = field.get(object);
		} catch (IllegalAccessException e) {
			log.error(e.getMessage(), e);
		}
		return result;
	}

	/**
	 * 直接设置对象属性,public/protected/private均可,无需set方法的存在.
	 * 
	 * @param object
	 * @param fieldName
	 */
	public static void setFieldValue(final Object object,
			final String fieldName, final Object value) {
		Field field = getDeclaredField(object, fieldName);
		if (field == null)
			throw new IllegalArgumentException("can not find field : "
					+ fieldName + " on object : " + object + ".");
		makeFieldAccessible(field);// 使属性可访问
		try {
			field.set(object, value);
		} catch (IllegalAccessException e) {
			log.error(e.getMessage(), e);
		}

	}

	/**
	 * 循环访问superClass直至Object,获取属性
	 * 
	 * @param object
	 * @param fieldName
	 * @return
	 */
	protected static Field getDeclaredField(final Object object,
			final String fieldName) {
		if (object == null)
			throw new IllegalArgumentException("object can not be null.");
		if (fieldName == null || fieldName.trim().equals(""))
			throw new IllegalArgumentException("fieldName must has value.");
		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException e) {
			}
		}
		return null;
	}

	/**
	 * 循环访问superClass直至Object,获取方法
	 * 
	 * @param object
	 * @param methodName
	 * @return
	 */
	protected static Method getDeclaredMethod(final Object object,
			final String methodName, Class clazz) {
		if (object == null)
			throw new IllegalArgumentException("object can not be null.");
		if (methodName == null || methodName.trim().equals(""))
			throw new IllegalArgumentException("fieldName must has value.");
		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredMethod(methodName, clazz);
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 强制field可访问.
	 * 
	 * @param field
	 */
	protected static void makeFieldAccessible(final Field field) {
		if (!Modifier.isPublic(field.getModifiers())
				|| !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
			field.setAccessible(true);
	}

	/**
	 * @see #getSuperClassType(Class, int)
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getSuperClassType(final Class clazz) {
		return getSuperClassType(clazz, 0);
	}

	/**
	 * 反射获取父类的泛型参数的类型.
	 * 
	 * @param clazz
	 * @param index
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Class getSuperClassType(final Class clazz, final int index) {
		Type type = clazz.getGenericSuperclass();
		if (!(type instanceof ParameterizedType))
			return Object.class;
		Type[] params = ((ParameterizedType) type).getActualTypeArguments();
		if (index >= params.length || index < 0)
			return Object.class;
		if (!(params[index] instanceof Class))
			return Object.class;
		return (Class) params[index];
	}

	/**
	 * 获取class的字段
	 * 
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	public static Field getDeclaredField(Class<?> clazz, String fieldName) {
		Field field = null;

		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				field = clazz.getDeclaredField(fieldName);
				return field;
			} catch (Exception e) {
				// 这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
				// 如果这里的异常打印或者往外抛，则就不会执行clazz =
				// clazz.getSuperclass(),最后就不会进入到父类中了
			}
		}

		return null;
	}

	/**
	 * 获取对应字段的值
	 * 
	 * @param field
	 * @param object
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public static Object getFieldValue(Field field, Object object)
			throws IllegalArgumentException, IllegalAccessException {
		field.setAccessible(true);
		return field.get(object);
	}

	/**
	 * 把对应字段设置为null
	 * 
	 * @param field
	 * @param object
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public static void setFieldNVL(Field field, Object object)
			throws IllegalArgumentException, IllegalAccessException {
		field.setAccessible(true);
		field.set(object, null);
	}

	/**
	 * 设置对应字段值
	 * 
	 * @param fieldName
	 * @param value
	 * @param object
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void setFieldValueUseSetMethod(String fieldName,
			Object value, Object object) {
		try {
			Method setMethod = getDeclaredMethod(
					object,
					"set" + fieldName.substring(0, 1).toUpperCase()
							+ fieldName.substring(1), value.getClass());
			setMethod.invoke(object, value);
		} catch (Exception e) {
			try {
				setFieldValue(object, fieldName, value);
			} catch (Exception e1) {
				log.error("set field(" + fieldName + ") value ocurrs errors!");
			}
		}
	}

	/**
	 * 把ID为空的关联字段过虑掉
	 * 
	 * @param object
	 */
	public static void filterObjectIdIsNVL(Object object) {
		if (object == null)
			return;
		Field[] fields = null;
		Class<?> clazz = object.getClass();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					Object value = getFieldValue(field, object);
					if (value instanceof IdEntity) {
						IdEntity identity = (IdEntity) value;
						if (identity != null && identity.getId() == null) {
							setFieldNVL(field, object);
						}
					}
				}
			} catch (Exception e) {
				log.error(e.getMessage());
			}
		}
	}
	
	//---以下这些方法 add by ljx 
	
		/**
		 * 根据get/is方法来获取对象的字段
		 * (不包含父类)
		 * @param obj
		 * @param field
		 * @return
		 */
		public static Object getFieldValueByGetMethod(Object obj, String field) {
			try {
				Method getMethod = obj.getClass().getMethod("get" + CommonUtil.firstToUppercase(field));
				return getMethod.invoke(obj);
			} catch (NoSuchMethodException e) {
				try {// 没有get方法找出is方法
					Method isMethod = obj.getClass().getMethod("is" + CommonUtil.firstToUppercase(field));
					return isMethod.invoke(obj);
				} catch (NoSuchMethodException e1) {
					log.info("未找到" + obj.getClass().toString() + "的" + field + "字段");
					return null;
				} catch (Exception e2) {
					log.error(e2.getMessage(), e2);
					return null;
				}
			} catch (Exception e) {
				log.error("未找到" + obj.getClass().toString() + "的" + field + "字段", e);
				return null;
			}
		}

		/**
		 * 获取对象对应属性值
		 * (不包含父类)
		 * @param obj
		 * @param property
		 * @return getPropertyValue(business,"user.id"); business.user.id
		 */
		public static Object getPropertyValue(Object obj, String property) {
			String[] fieldFloor = property.split("\\.");
			Object value = obj;
			for (int i = 0; i < fieldFloor.length; i++) {
				//edit by yangliwei
				//这里之前会出现关联对象取不到属性值问题
//				value = getFieldValueByGetMethod(obj, fieldFloor[i]);
				value = getFieldValueByGetMethod(value, fieldFloor[i]);
				if (value == null) {
					return null;
				}
			}
			return value;
		}

		/**
		 * 获取该类(不包含父类)包含get属性字段的属性名
		 * 
		 * @param clazz
		 * @return
		 */
		public static List<String> getFieldsByGet(Class<?> clazz) {
			Method[] methods = clazz.getDeclaredMethods();// TODO 先测测看是不是这些方法再继续
			List<String> fieldNameList = new ArrayList<String>();
			for (Method method : methods) {
				String field = "";
				
				if(method.getName().startsWith("get")){//是get方法
					//field的去get化
					field = CommonUtil.removePrefix(method.getName(), "get");
				}else if (method.getName().startsWith("is")) {//是is方法
					//field的去is化
					field = CommonUtil.removePrefix(method.getName(), "is");
				}else{//如果都不是就下一个
					continue;
				}
				//此时首字母是大写的，转换一下
				field = CommonUtil.firstToLowercase(field);
				fieldNameList.add(field);
			}
			return fieldNameList;
		}
		
		/**
		 * 如果该对象有这个属性，则设置对象中属性的值(set方法赋值)
		 * 不包含父类
		 * @param obj
		 * @param fieldName
		 * @param value
		 * @return 1 设置成功 -1 没有对应属性 -2 由于其他原因，设置失败。
		 */
		public static int setFieldBySetMethod(Object obj, String fieldName, Object value) {
			try {
				Method setMethod = obj.getClass().getMethod("set" + CommonUtil.firstToUppercase(fieldName), value.getClass());
				setMethod.invoke(obj, value);
			} catch (NoSuchMethodException e) {
				log.info(obj.getClass().getName()+"没有该字段"+fieldName+"的set方法");
				return -1;
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				return -2;
			}
			return 1;
		}
}